﻿using System.Drawing;

namespace SSS.AlphaNN.Logic
{
    using System;

    public static class Mathematic
    {
        [Flags]
        public enum FunctionActivationTypes
        {
            /// <summary>
            /// Сумма входных сигналов равна выходу
            /// </summary>
            Equals=0x0,

            /// <summary>
            /// Пороговая функция активации
            /// </summary>
            Step=0x1,

            /// <summary>
            /// Униполярная функция
            /// </summary>
            Unipolar=0x2,

            /// <summary>
            /// Биполярная функция
            /// </summary>
            Bipolar=0x4
        }

        /// <summary>
        /// Функция которая просто возвращает результат умножая его на константу. Функция активации 
        /// "придуманная" мною для расчета функций (0)
        /// </summary>
        /// <param name="a"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        public static double EqualsFunctions(double a, double x)
        {
            return a*x;
        }

        /// <summary>
        /// Производная функции
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        public static double DiffEqualsFunctions(double a)
        {
            return a;
        }

        /// <summary>
        /// Нелинейная функция активации (1)
        /// </summary>
        /// <param name="summaValues">сумма произведений входных сигналов и весов</param>
        /// <returns>сигнал выход</returns>
        public static double NotLinedFunctionActivision(double step, double beta, double alpha, double summaValues)
        {
            return (summaValues >= step) ? alpha : beta;
        }

        /// <summary>
        /// Униполярная функция активации (2)
        /// </summary>
        /// <param name="alpha">параметр который задаётся пользователем</param>
        /// <param name="x">сумма произведений входных сигналов и весов</param>
        /// <returns>сигнал выход</returns>
        public static double UnipolarFunction(double alpha, double x)
        {
            return 1.0D / (1 + Math.Exp(-alpha * x));
        }

        /// <summary>
        /// Производная униполярной функции активации (2)
        /// </summary>
        /// <param name="alpha">параметр который задаётся пользователем</param>
        /// <param name="x">сумма произведений входных сигналов и весов</param>
        /// <returns>сигнал выход</returns>
        public static double DiffUnipolarFunction(double alpha, double x)
        {
            double y = UnipolarFunction(alpha, x);

            return (alpha * y*(1 - y) );  
        }

        
        /// <summary>
        /// Биполярная функция активации (3)
        /// </summary>
        /// <param name="alpha">Параметр который подбирается пользователем</param>
        /// <param name="x">сумма произведений входных сигналов и весов</param>
        /// <returns>выходной сигнал</returns>
        public static double BipolarFunction(double alpha, double x)
        {
            return Math.Tanh(alpha * x);
        }

        /// <summary>
        /// Производная биполярной функции активации (3)
        /// </summary>
        /// <param name="alpha">Параметр который подбирается пользователем</param>
        /// <param name="x">сумма произведений входных сигналов и весов</param>
        /// <returns>выходной сигнал</returns>
        public static double DiffBipolarFunction(double alpha, double x)
        {
            double y = BipolarFunction(alpha, x);
            return alpha*(1 - y*y);
        }

        
        public static int LengthVector(Point a, Point b)
        {
            return (int)(Math.Sqrt((b.X - a.X)*(b.X - a.X) - (b.Y - a.Y)*(b.Y - a.Y)));
        }

        /// <summary>
        /// Транспонирование матрицы
        /// </summary>
        /// <param name="input">Входное значение</param>
        /// <returns>Транспонированная матрица</returns>
        public static TypeWeight[][] Transposition(TypeWeight[][] input)
        {
            TypeWeight[][] result = new TypeWeight[input[0].Length][];

            for ( int i=input[0].Length-1, k=0; i>=0; i--, k++ )
            {
                result[k] = new TypeWeight[input.Length];
                for ( int j1=input.Length-1, l=0; j1>=0; j1--, l++ )
                {

                    result[k][l] = input[j1][i];
                }
            }
            
            return result;
        }
        
    }
}
